Skip to content

feat(coprocessor): add cargo-llvm-cov code coverage to Rust CI workflows#2086

Open
PanGan21 wants to merge 8 commits intomainfrom
panos/add-coverage-tool
Open

feat(coprocessor): add cargo-llvm-cov code coverage to Rust CI workflows#2086
PanGan21 wants to merge 8 commits intomainfrom
panos/add-coverage-tool

Conversation

@PanGan21
Copy link

Summary

  • Adds cargo-llvm-cov (LLVM source-based instrumentation) to all 3 Rust CI test workflows: coprocessor, kms-connector, and sdk/rust-sdk
  • Coverage replaces cargo test (not in addition to it) so overhead is minimal (~10-20% compile time)
  • Coverage results are printed to the GitHub Actions job summary tab (non-blocking, no artifacts uploaded)
  • Adds per-workspace coverage thresholds in ci/coverage-thresholds.json (40%/50%/60%) for future enforcement

Related: https://github.com/zama-ai/fhevm-internal/issues/1146

@PanGan21 PanGan21 requested review from a team and dartdart26 as code owners March 10, 2026 16:08
@cla-bot cla-bot bot added the cla-signed label Mar 10, 2026
@Eikix
Copy link
Contributor

Eikix commented Mar 10, 2026

@claude /pr-review

@claude
Copy link

claude bot commented Mar 10, 2026

Claude finished @Eikix's task in 8m 8s —— View job


[AUTOMATED]

PR Review: feat(ci): add cargo-llvm-cov code coverage to Rust CI workflows

  • Gather context and read changed files
  • Run parallel review agents (bug hunting, error handling)
  • Validate and deduplicate findings
  • Post final review

Summary

Good initiative adding LLVM source-based coverage instrumentation to the Rust CI workflows. The approach of replacing cargo test with cargo llvm-cov (rather than running both) is sensible to keep overhead low. The changes are well-structured and consistent across the three workflows. I found a few issues worth addressing:


🔴 Issue 1: Coverage thresholds are dead code — never enforced

Files: ci/coverage-thresholds.json + all 3 workflow files
Confidence: 95/100

The ci/coverage-thresholds.json file defines thresholds (60 for all components), and all three workflows reference it in their paths-filter sections. However, no workflow step ever reads, parses, or compares actual coverage against these thresholds. Coverage can silently drop to 0% and CI will still pass green.

The only effect of this file today is triggering CI re-runs when the JSON changes — which does nothing useful since the thresholds aren't enforced.

The PR description mentions this is "for future enforcement," which is fine — but I'd recommend either:

  • Adding a TODO comment in the workflows referencing the thresholds file, or
  • Implementing basic enforcement now with cargo llvm-cov --fail-under-lines <threshold>

Also, the PR description states thresholds of "40%/50%/60%" but the actual file has all three set to 60.


🟡 Issue 2: Coverage profile inherits opt-level = 3 — may produce inaccurate coverage

File: coprocessor/fhevm-engine/Cargo.toml, lines 115-118
Confidence: 85/100

[profile.coverage]
inherits = "release"
lto = false
codegen-units = 16

This inherits from [profile.release] which has opt-level = 3. At high optimization levels, LLVM aggressively inlines functions, eliminates dead code, and merges branches — all of which distort coverage data. The cargo-llvm-cov documentation and LLVM coverage best practices recommend lower optimization levels for accurate coverage.

Consider adding opt-level = 1 (matching the existing [profile.local] pattern) or opt-level = 0:

[profile.coverage]
inherits = "release"
opt-level = 1
lto = false
codegen-units = 16

Fix this →


🟡 Issue 3: 2>/dev/null in coverage summary silently swallows errors

Files: All 3 workflow files (coverage summary steps)
Confidence: 95/100

cargo llvm-cov report --workspace --profile coverage >> "$GITHUB_STEP_SUMMARY" 2>/dev/null || echo 'No coverage data available' >> "$GITHUB_STEP_SUMMARY"

When cargo llvm-cov report fails, the stderr is discarded entirely. The actual error could be corrupted .profraw files, LLVM version mismatches, filesystem issues, etc. — all hidden behind a generic "No coverage data available" message.

Consider redirecting stderr to a separate line in the summary or to the step log instead:

cargo llvm-cov report --workspace --profile coverage >> "$GITHUB_STEP_SUMMARY" 2>&1 || echo 'No coverage data available' >> "$GITHUB_STEP_SUMMARY"

Or capture stderr separately:

if ! cargo llvm-cov report --workspace --profile coverage >> "$GITHUB_STEP_SUMMARY" 2>/tmp/cov-err.log; then
  echo 'No coverage data available' >> "$GITHUB_STEP_SUMMARY"
  echo "<details><summary>Error details</summary>" >> "$GITHUB_STEP_SUMMARY"
  echo "" >> "$GITHUB_STEP_SUMMARY"
  cat /tmp/cov-err.log >> "$GITHUB_STEP_SUMMARY"
  echo "</details>" >> "$GITHUB_STEP_SUMMARY"
fi

🟡 Issue 4: Coprocessor coverage summary may hang due to DATABASE_URL with stopped DB

File: .github/workflows/coprocessor-cargo-tests.yml, lines 118-126
Confidence: 75/100

The coverage summary step runs with if: always() and sets DATABASE_URL=postgresql://.... If the PostgreSQL container or the test step itself has already failed/been torn down, the cargo llvm-cov report command might attempt to connect to the database (if workspace compilation triggers sqlx macros). Combined with 2>/dev/null, any connection timeout would be silently hidden. This is likely not an issue for a pure report command, but worth verifying.


Nit: Missing rust-toolchain.toml for sdk/rust-sdk

The PR adds components = ["llvm-tools-preview"] to coprocessor/fhevm-engine/rust-toolchain.toml and kms-connector/rust-toolchain.toml, but sdk/rust-sdk doesn't have a rust-toolchain.toml at all. This isn't a CI bug (the workflow installs the component), but local cargo llvm-cov usage in sdk/rust-sdk/ would fail without the component.


✅ What looks good

  • Pinned action SHAstaiki-e/install-action@a37010ded... is properly pinned with a comment tag
  • Cache key change — The cargo-coverage- prefix prevents cache pollution between coverage and non-coverage builds
  • Non-blocking summary — Coverage is printed to job summary without failing the build, which is appropriate for initial rollout
  • Consistent pattern — All 3 workflows follow the same structure, making them maintainable
  • if: always() on summary — Good practice to show coverage data even when tests fail

@PanGan21 PanGan21 changed the title feat(ci): add cargo-llvm-cov code coverage to Rust CI workflows feat(common): add cargo-llvm-cov code coverage to Rust CI workflows Mar 10, 2026
@PanGan21 PanGan21 removed request for a team March 10, 2026 16:36
@PanGan21 PanGan21 changed the title feat(common): add cargo-llvm-cov code coverage to Rust CI workflows feat(coprocessor): add cargo-llvm-cov code coverage to Rust CI workflows Mar 10, 2026
@PanGan21 PanGan21 force-pushed the panos/add-coverage-tool branch from 1803cc8 to af7a1fd Compare March 10, 2026 16:38
@Eikix
Copy link
Contributor

Eikix commented Mar 10, 2026

@claude /pr-review

@claude
Copy link

claude bot commented Mar 10, 2026

Claude finished @Eikix's task in 7m 25s —— View job


[AUTOMATED]

PR Review: feat(coprocessor): add cargo-llvm-cov code coverage to Rust CI workflows

  • Gather context and read changed files
  • Run parallel review agents (bug hunting, error handling)
  • Validate and deduplicate findings
  • Post final review

Summary

Clean, well-structured CI change that replaces cargo test --release with cargo llvm-cov --workspace --profile coverage in the coprocessor workflow. The author has already addressed multiple items from the earlier review (removed dead thresholds file, set opt-level = 1, scoped to coprocessor only). No bugs found. One minor suggestion below.

I ran three parallel review agents (2× bug hunter, 1× error handling auditor) and validated all findings:

  • Bug hunters: No real bugs found. The cargo llvm-cov invocation correctly passes workspace, profile, and test harness arguments. Environment variables are properly set. The coverage profile correctly inherits from release without changing debug_assertions behavior.
  • Error handling auditor: Flagged if: always() as potentially masking test failures — validated as false positive. GitHub Actions job results are only ever escalated to worse states (runner source); a succeeding cleanup step cannot undo a prior failure.

🟢 No Blocking Issues


Nit: 2>/dev/null hides diagnostic context on report failure

File: .github/workflows/coprocessor-cargo-tests.yml, line 121

REPORT=$(DATABASE_URL=... cargo llvm-cov report --workspace --profile coverage 2>/dev/null) || true

When cargo llvm-cov report fails (e.g., corrupted .profraw files, LLVM version mismatch), the error details are discarded entirely. The user sees only the generic "No coverage data available" fallback. Since this is a non-blocking reporting step, the impact is low — but surfacing the error would help debug coverage tooling issues. Consider:

REPORT=$(DATABASE_URL=... cargo llvm-cov report --workspace --profile coverage 2>&1) || true

This way stderr content would be captured into $REPORT alongside stdout, and displayed in the summary block if present. Not blocking — the current approach is fine for initial rollout.


✅ What looks good

Aspect Assessment
Pinned action SHAs taiki-e/install-action@a37010ded... properly pinned with version comment
Cache key isolation cargo-coverage- prefix prevents pollution between coverage and release builds
Coverage profile opt-level = 1, debug = 1, lto = false — good balance of accuracy vs compile time
Non-blocking summary Coverage printed to job summary without failing the build — appropriate for rollout
if: always() on summary Correct pattern — shows coverage data even when tests fail, without masking failures
rust-toolchain.toml llvm-tools-preview component enables local cargo llvm-cov usage too
Toolchain pinning Changed from stable to "1.91.1" — matches rust-toolchain.toml, good for reproducibility

Previous Review Items — Status

The earlier review raised several issues. Here's where they stand after the author's subsequent commits:

# Previous Issue Status
1 Coverage thresholds are dead code Fixedci/coverage-thresholds.json removed in af7a1fdc
2 Coverage profile inherits opt-level = 3 Fixed — now uses opt-level = 1 in af7a1fdc
3 2>/dev/null swallows errors Nit — kept as-is, acceptable for initial rollout (see above)
4 DB connection hang risk Not a real issuecargo llvm-cov report reads profiling data from disk, doesn't connect to DB

LGTM — this is ready to merge. 🚀

@mergify
Copy link

mergify bot commented Mar 10, 2026

🧪 CI Insights

Here's what we observed from your CI run for b610ebf.

🟢 All jobs passed!

But CI Insights is watching 👀

@PanGan21 PanGan21 force-pushed the panos/add-coverage-tool branch from 1422c9c to 4ea96e1 Compare March 10, 2026 22:06
@PanGan21
Copy link
Author

@claude /pr-review

@claude
Copy link

claude bot commented Mar 11, 2026

Claude finished @PanGan21's request.View run

Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[AUTOMATED]

Code Review — PR #2086

Summary

This PR adds cargo-llvm-cov code coverage instrumentation to the coprocessor Rust CI workflow. It replaces cargo test --release with cargo llvm-cov using a new [profile.coverage] Cargo profile, and writes coverage results to the GitHub Actions job summary.

Files reviewed:

  • .github/workflows/coprocessor-cargo-tests.yml — CI workflow changes
  • coprocessor/fhevm-engine/Cargo.toml — New [profile.coverage] section
  • coprocessor/fhevm-engine/rust-toolchain.toml — Added llvm-tools-preview component

What looks good

  • Actions are properly pinned to SHA hashes (taiki-e/install-action, dtolnay/rust-toolchain)
  • Cache key updated to avoid conflicts with old release-profile artifacts
  • The [profile.coverage] sensibly inherits from release with debug = 1 for source mapping and reduced opt-level for better instrumentation accuracy
  • Test step correctly does not have || true, so test failures will still fail the workflow
  • The if: always() on the report step is appropriate for informational output
  • rust-toolchain.toml change is consistent with the workflow toolchain pin

Issues found: 2 (non-blocking)

See inline comments below.

@claude
Copy link

claude bot commented Mar 11, 2026

The review has been posted successfully. Here's a summary of what was done:

Review Complete ✅

I posted a code review on PR #2086 with:

Review Summary (COMMENT — non-blocking)

The PR is a solid CI enhancement that adds code coverage instrumentation. All actions are properly SHA-pinned, the coverage profile is well-configured, and test failures correctly propagate to fail the workflow.

2 Non-blocking Inline Comments (Nits)

  1. Missing --workspace on cargo llvm-cov report (line 120, confidence 82/100) — The test-run step instruments all 9 workspace crates with --workspace, but the report step omits it. This could produce an incomplete coverage report. Suggested adding --workspace to the report command.

  2. Error messages rendered as coverage data (line 117, confidence 80/100) — The 2>&1 + || true pattern means if the report command fails, the error message gets displayed inside the markdown code block as if it were valid coverage data. The fallback "No coverage data available" message will never trigger in practice. Suggested using the exit code to distinguish success from failure.

Validated Non-Issues

  • cargo llvm-cov clean on first run — validated as likely safe (clean commands are typically idempotent)
  • Profile behavioral differences (--release--profile coverage) — no semantic changes; debug = 1 only controls debuginfo, not debug_assertions
  • Cache key change — intentional and correct to avoid mixing release/coverage artifacts

@PanGan21
Copy link
Author

@claude /pr-review

@claude
Copy link

claude bot commented Mar 11, 2026

Claude finished @PanGan21's request.View run

Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[AUTOMATED]

Code Review

Overall this is a clean, well-structured PR that adds code coverage instrumentation to the Rust CI workflow. The action pinning, cache key separation, profile configuration, and rust-toolchain.toml changes all follow established project conventions. One issue found below.

Checked for: bugs, guideline compliance, error handling.

@claude
Copy link

claude bot commented Mar 11, 2026

The review has been posted successfully. Here's a summary of the review:

Review Summary for PR #2086

PR: feat(coprocessor): add cargo-llvm-cov code coverage to Rust CI workflows

What was checked

  • Bug hunting (2 independent passes)
  • Guideline compliance against established project patterns
  • Error handling audit of shell scripts in the workflow

Findings

1 validated issue posted:

Severity File Issue Confidence
Bug coprocessor-cargo-tests.yml:131 Missing --workspace flag on cargo llvm-cov report — report will exclude coverage from workspace members that were instrumented during the test run 85/100

What passed review

  • ✅ Action pinning follows project conventions (full SHA + version comment)
  • ✅ Toolchain version aligns with rust-toolchain.toml
  • ✅ Cache key separation prevents cross-contamination with non-coverage builds
  • [profile.coverage] follows the existing [profile.local] pattern
  • rust-toolchain.toml update is consistent
  • ✅ Error handling in the report generation step is reasonable for a non-blocking summary step
  • if: always() is appropriate standard CI practice for report/summary steps

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants